package com.zhengxing.jienci.filter;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.server.ServerWebExchange;

import com.zhengxing.jienci.constant.MDA;
import com.zhengxing.jienci.exception.GateWayException;
import com.zhengxing.jienci.exception.SystemErrorType;
import com.zhengxing.jienci.respository.UserMapper;
import com.zhengxing.jienci.support.SysUser;
import com.zhengxing.jienci.support.TokenInfo;
import com.zhengxing.jienci.util.FastJsonUtil;

import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;

@Component
@Slf4j
public class AuthorizationFilter implements GlobalFilter, Ordered, InitializingBean{
	
	@Autowired
	private RestTemplate restTemplate;
	
	@Autowired
	private UserMapper userMapper;
	
	private Set<String> shouldSkipUrl = new HashSet<String>();
	
	private AntPathMatcher pathMatcher = new AntPathMatcher();
	
	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		String path = exchange.getRequest().getURI().getPath();
		log.info("当前请求网关认证授权路径为：{}", path);
		if(shouldSkip(path)) {
			log.info("路径：{}无需认证", path);
			return chain.filter(exchange);
		}
		String authorization = exchange.getRequest().getHeaders().getFirst("Authorization");
		if(StringUtils.isBlank(authorization)) {
			log.warn("请求：{}需要授权认证", path);
			throw new GateWayException(SystemErrorType.UNAUTHORIZED_HEADER_IS_EMPTY);
		}
		TokenInfo tokenInfo = null;
		try {
			tokenInfo = obtainTokenInfo(authorization);
		} catch (Exception e) {
			throw new GateWayException(SystemErrorType.INVALID_TOKEN);
		}
		Map<String, Object> columnMap = new HashMap<String, Object>();
		columnMap.put("username", tokenInfo.getUser_name());
		List<SysUser> users = userMapper.selectByMap(columnMap);
		tokenInfo.setUser_id(users.get(0).getId());
		//向请求头中放信息，记得build
		ServerHttpRequest request = exchange.getRequest().mutate().header("tokenInfo", tokenInfo == null ? "" : FastJsonUtil.toJSON(tokenInfo)).build();
		//将新的request添加到exchange中
		exchange.mutate().request(request).build();
		exchange.getAttributes().put("tokenInfo", FastJsonUtil.toJSON(tokenInfo));
		return chain.filter(exchange);
	}
	
	/**
	 * @author yyh
	 * 校验是否需要跳过认证授权
	 */
	private boolean shouldSkip(String path) {
		for (String pattern : shouldSkipUrl) {
			if(pathMatcher.match(pattern, path)) {
				return true;
			}
		}
		return false;
	}
	
	private TokenInfo obtainTokenInfo(String authorization) {
		String token = StringUtils.substringAfter(authorization, "bearer ");
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
		headers.setBasicAuth(MDA.CLIENT_ID, MDA.CLIENT_SECRET);
		MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
		params.add("token", token);
		HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<MultiValueMap<String,String>>(params, headers);
		ResponseEntity<TokenInfo> response = restTemplate.exchange(MDA.CHECK_TOKEN_URL, HttpMethod.POST, requestEntity, TokenInfo.class);
		log.info("获取用户信息：{}", response.getBody().toString());
		return response.getBody();
	}
	
	
	/**
	 * 值越小，优先级越高
	 */
	@Override
	public int getOrder() {
		return 0;
	}
	
	
	@Override
	public void afterPropertiesSet() throws Exception {
		shouldSkipUrl.add("/sso/authentication/openid");
		shouldSkipUrl.add("/sso/authentication/mobile");
		shouldSkipUrl.add("/sso/authentication/form");
		shouldSkipUrl.add("/sso/code/sms");
		shouldSkipUrl.add("/user/userFunction/tree");
		shouldSkipUrl.add("/content/upload/**");
		shouldSkipUrl.add("/*/v2/api-docs");
	}
	

}
